/**
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

package pittypat.data;

import java.math.BigDecimal;
import java.sql.*;
import java.time.LocalDate;
import java.time.LocalTime;

import java.time.LocalDateTime;
import java.util.UUID;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * 从数据库中读取一个或多个结果集合的数据行。
 * <p>
 * 针对不同的数据库提供不同的实现，完成对目标数据库返回结果集合的读取。
 */
public abstract class DbDataReader implements AutoCloseable {
	private static final Logger LOGGER = LogManager.getLogger(DbDataReader.class);

	private Statement statement;
	private ResultSet resultSet;

	/**
	 * 使用目标数据集合初始化 DbDataReader 类的新实例。
	 * 
	 * @param statement
	 *            目标数据库命令。
	 * @throws SQLException
	 */
	protected DbDataReader(Statement statement) throws SQLException {
		this.statement = statement;
		// 第一个结果集合
		this.resultSet = statement.getResultSet();
	}

	/**
	 * 关闭当前结果集合，但是不负责关闭目标命令。
	 * 
	 * @throws SQLException
	 */
	@Override
	public void close() throws SQLException {
		if (this.resultSet != null) {
			this.resultSet.close();
			this.resultSet = null;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Object getObject(String name, Object defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getObject(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个字符串值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public String getString(String name, String defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getString(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个布尔值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Boolean getBoolean(String name, Boolean defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getBoolean(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从数据行中获取一个 UUID 值。
	 * 
	 * @param resultSet
	 *            结果集合。
	 * @param name
	 *            列名称。
	 * @return 一个 UUID 值，如果无法转换为 UUID，则返回 null。
	 * @throws SQLException
	 */
	protected abstract UUID getUuid(ResultSet resultSet, String name) throws SQLException;

	/**
	 * 从 DbDataReader 中获取一个 Uuid 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public UUID getUuid(String name, UUID defaultValue) {
		try {
			UUID uid = getUuid(this.resultSet, name);
			return uid == null ? defaultValue : uid;
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个字节数组值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public byte[] getByteArray(String name, byte[] defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getBytes(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Byte 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Byte getByte(String name, Byte defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getByte(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Short 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Short getShort(String name, Short defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getShort(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Integer 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Integer getInteger(String name, Integer defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getInt(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Long 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Long getLong(String name, Long defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getLong(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Decimal 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public BigDecimal getDecimal(String name, BigDecimal defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getBigDecimal(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Float 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Float getFloat(String name, Float defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getFloat(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Double 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public Double getDouble(String name, Double defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			} else {
				return this.resultSet.getDouble(index);
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 DateTime 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public LocalDateTime getDateTime(String name, LocalDateTime defaultValue) {
		try {
			Timestamp timestamp = this.resultSet.getTimestamp(name);
			if (timestamp == null) {
				return defaultValue;
			} else {
				return timestamp.toLocalDateTime();
			}
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Date 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public LocalDate getDate(String name, LocalDate defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			}

			Date date = this.resultSet.getDate(index);
			return date == null ? null : date.toLocalDate();
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 从 DbDataReader 中获取一个 Time 值。
	 * 
	 * @param name
	 *            列的名称。
	 * @param defaultValue
	 *            当没有找到列时，或者列的值为数据库空值时应该返回的默认值。
	 */
	public LocalTime getTime(String name, LocalTime defaultValue) {
		int index = 0;
		try {
			index = this.resultSet == null ? 0 : this.resultSet.findColumn(name);
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			index = 0;
		}

		try {
			if (index < 1) {
				return defaultValue;
			}

			Time time = this.resultSet.getTime(index);
			return time == null ? null : time.toLocalTime();
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return defaultValue;
		}
	}

	/**
	 * 读取下一行数据。
	 * 
	 * @return 如果存在可用的行，返回 true，否则返回 false。
	 */
	public boolean read() {
		try {
			return this.resultSet == null ? false : this.resultSet.next();
		} catch (SQLException e) {
			LOGGER.error(e.getMessage(), e);
			return false;
		}
	}

	/**
	 * 读取下一个结果集合。
	 * 
	 * @return 如果存在可用的结果集合，返回 true，否则返回 false。
	 */
	public boolean nextResult() {
		try {
			// 首先关闭原结果集合
			if (this.resultSet != null) {
				this.resultSet.close();
				this.resultSet = null;
			}

			// 读取下一个结果集合
			if ((statement.getMoreResults()) && (statement.getUpdateCount() == -1)) {
				this.resultSet = statement.getResultSet();
			}
		} catch (SQLException e) {
			this.resultSet = null;
			LOGGER.error(e.getMessage(), e);
		}

		return this.resultSet != null;
	}
}
